#pragma once 

#include "InetAddress.h"
#include "Connection.h"

#include"MsgBuffer.h"
#include"EventLoop.h"

#include<list>
#include<functional>
#include<memory>



namespace tmms
{
    namespace network
    {
        class UdpSocket;
        using UdpSocketPtr = std::shared_ptr<UdpSocket>;
        using UdpSocketMessageCallback = std::function<void(const InetAddress &addr,MsgBuffer &buf)>;
        using UdpSocketWriteCompleteCallback = std::function<void(const UdpSocketPtr &)>;
        using UdpSocketCloseConnectionCallback  =  std::function<void(const UdpSocketPtr &)>;
        using UdpSocketTimeoutCallback = std::function<void(const UdpSocketPtr &)>;
        struct UdpTimeoutEntry;

        struct UdpBufferNode:BufferNode
        {
            UdpBufferNode(void *buf,size_t s,struct sockaddr* saddr,socklen_t len)
            :BufferNode(buf,s),sock_addr(saddr),sock_len(len)
            {}
            struct sockaddr *sock_addr{nullptr}; //数据
            socklen_t sock_len{0};//数据大小
        };
        using UdpBufferNodePtr =  std::shared_ptr<UdpBufferNode>;

        class UdpSocket : public Connection
        {
        public:
            UdpSocket(EventLoop * loop,
                    int socketfd,
                    const InetAddress &localAddr,
                    const InetAddress &peerAddr);

            void SetCloseCallback(const UdpSocketCloseConnectionCallback &cb);
            void SetCloseCallback( UdpSocketCloseConnectionCallback &&cb);
            void SetRecvMsgCallback(const UdpSocketMessageCallback &cb);
            void SetRecvMsgCallback(UdpSocketMessageCallback &&cb);
            void SetWriteCompleteCallback(const UdpSocketWriteCompleteCallback & cb);
            void SetWriteCompleteCallback(UdpSocketWriteCompleteCallback &&cb);


            void SetTimeoutCallback(int timeout,const UdpSocketTimeoutCallback &cb);
            void SetTimeoutCallback(int timeout,UdpSocketTimeoutCallback &&cb);
            void EnableCheckIdleTimeout(int32_t max_time);

            void Send(std::list<UdpBufferNodePtr>& list);
            void Send(const char* buf,size_t size,struct sockaddr* addr,socklen_t len);
          
            
            void OnTimeOut();
            void OnError(const std::string &msg) override;
            void OnRead() override;
            void OnWrite() override;
            void OnClose() override;
            void ForceClose() override;


            ~UdpSocket();

        private:
            void ExtenLife();
            void SendInLoop(std::list<UdpBufferNodePtr>& list);
            void SendInLoop(const char* buf,size_t size,struct sockaddr* saddr,socklen_t len);
            std::list<UdpBufferNodePtr> buffer_list_;
            bool closed_{false};
            int32_t max_idle_time_{30};
            std::weak_ptr<UdpTimeoutEntry> timeout_entry_;
            MsgBuffer message_buffer_;
            UdpSocketMessageCallback message_cb_;
            int32_t message_buffer_size{65535};
            UdpSocketWriteCompleteCallback write_complete_cb_;
            UdpSocketCloseConnectionCallback close_cb_;

        };

        struct UdpTimeoutEntry
        {
            public:
            UdpTimeoutEntry(const UdpSocketPtr &c)  
            :conn(c){

            };

            std::weak_ptr<UdpSocket> conn;

            ~UdpTimeoutEntry(){
                auto c =conn.lock();//尝试从weak_ptr获取一个有效的shared_ptr
                if(c)
                {
                    c->OnTimeOut();  //用它的时候，这个class TcpConnection 必须先定义才可以使用
                }
            };

        };

    }
}